﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Model01.Management;
using Model01.Modifier;
using Model01.Transportation;

using modelPoint = Model01.Objects.Point;
using modelSize = Model01.Objects.Size;

namespace GraficTester
{    
    public partial class Form1 : Form
    {
        #region Fields

        private PictureBox pictureBox;
        private Bitmap backGroundImage;
        private Bitmap carImage;
        private Dictionary<Streetlight, Colors> streetlightColors = new Dictionary<Streetlight, Colors>();

        #endregion

        public Form1()
        {
            InitializeComponent();
            backGroundImage = new Bitmap(Image.FromFile(Directory.GetCurrentDirectory() + @"\Sources\road1.bmp"));
            carImage = new Bitmap(Image.FromFile(Directory.GetCurrentDirectory() + @"\Sources\Car.bmp"));

            this.Width = backGroundImage.Width + 15;
            this.Height = backGroundImage.Height + 20;

            pictureBox = new PictureBox() { Parent = this, Size = this.Size, Image = backGroundImage };
            pictureBox.MouseDoubleClick += new MouseEventHandler(Form1_DoubleClick);
            pictureBox.MouseClick += new MouseEventHandler(pictureBox_MouseClick);

            Manager.MaxSpeed = 60;
            Manager.Init();

            //Deceleration = 7.7: тормаз. путь в 50 м со 100 км/ч; Acceleration = 2.3: ускорение до 100 км/ч за 12 сек. 
            Manager.cars = new List<CityCar>()
            {
                new CityCar(2, 303, new modelSize(36, 16)) { Destination = new modelPoint(1000, 303), Acceleration = 2.3, Deceleration = 7.7 },
                new CityCar(1000, 376, new modelSize(36, 16)) { Destination = new modelPoint(30, 376), Acceleration = 2.3, Deceleration = 7.7, CurrentAngle = Math.PI },
                new CityCar(475, 13, new modelSize(36, 16)) { Destination = new modelPoint(475, 700), Acceleration = 2.3, Deceleration = 7.7, CurrentAngle = Math.PI / 2 },
                new CityCar(543, 700, new modelSize(36, 16)) { Destination = new modelPoint(543, 13), Acceleration = 2.3, Deceleration = 7.7, CurrentAngle = 3 * Math.PI / 2 }
            };

            int switchTime = 3000;
            Manager.streetlights = new List<Streetlight>() 
            {
                new Streetlight(switchTime, 417, 289, new modelSize(1, 1)), 
                new Streetlight(switchTime, 600, 289, new modelSize(1, 1)),
                new Streetlight(switchTime, 417, 416, new modelSize(1, 1)), 
                new Streetlight(switchTime, 600, 416, new modelSize(1, 1)),
                new Streetlight(switchTime, 460, 265, new modelSize(1, 1)), 
                new Streetlight(switchTime, 460, 446, new modelSize(1, 1)),
                new Streetlight(switchTime, 574, 265, new modelSize(1, 1)), 
                new Streetlight(switchTime, 574, 446, new modelSize(1, 1))
            };
            for (int i = 0; i < Manager.streetlights.Count; i++)
            {
                Manager.streetlights[i].OnLightChange += new OnLihgtChangeEvent(streetlight_OnLightChange);
                streetlightColors.Add(Manager.streetlights[i], new Colors());
                if (i < 4)
                    Manager.streetlights[i].StartFromGreen();
                else
                    Manager.streetlights[i].StartFromRed();
            }
            Manager.OnPaint += new EventHandler(Manager_OnPaint);
            Thread.Sleep(switchTime);
            Manager.Start();
        }              

        #region Methods

        private void Manager_OnPaint(object sender, EventArgs e)
        {
            Thread paintThread = new Thread(RedrawModel);
            paintThread.Start();
        }

        private void streetlight_OnLightChange(object sender, LihgtChangeEventArgs e)
        {            
            ThreadStart d = () =>
            {
                Colors color = new Colors();
                switch (e.Light)
                {
                    case Lights.Green:
                        {
                            color.MainColor = Color.FromArgb(0, 255, 0);
                            color.Light = Color.FromArgb(130, 255, 130);
                        }
                        break;
                    case Lights.Yellow:
                        {
                            color.MainColor = Color.FromArgb(255, 200, 0);
                            color.Light = Color.FromArgb(255, 225, 130);
                        }
                        break;
                    case Lights.Red:
                        {
                            color.MainColor = Color.FromArgb(255, 0, 0);
                            color.Light = Color.FromArgb(255, 130, 130);
                        }
                        break;
                }
                color.BorderOut = Color.FromArgb(20, color.MainColor);
                color.BorderOutCenter = Color.FromArgb(40, color.MainColor);
                color.BorderCenter = Color.FromArgb(60, color.MainColor);
                color.BorderInCenter = Color.FromArgb(80, color.MainColor);
                color.BorderIn = Color.FromArgb(100, color.MainColor);
                streetlightColors[(Streetlight)sender] = color;
                Thread.CurrentThread.Abort();
            };
            Thread lightSwither = new Thread(d);
            lightSwither.Start();
        }

        private void PaintStreetlight(Graphics g, Streetlight streetlight)
        {
            int x = streetlight.X, y = streetlight.Y;//, N = 10;
            Colors color = streetlightColors[streetlight];
            g.FillEllipse(new SolidBrush(color.MainColor), x - 6, y - 1, 11, 11);
            g.FillEllipse(new SolidBrush(color.Light), x - 4, y + 1, 7, 7);
            g.FillRectangle(new SolidBrush(Color.White), x - 1, y + 4, 2, 2);
            //g.FillRectangle(new SolidBrush(color.Black), x, y, N, N);
            g.DrawArc(new Pen(color.BorderOut, 1), x - 11, y - 6, 21, 21, 0, 360);
            g.DrawArc(new Pen(color.BorderOutCenter, 2), x - 10, y - 5, 19, 19, 0, 360);
            g.DrawArc(new Pen(color.BorderCenter, 2), x - 9, y - 4, 17, 17, 0, 360);
            g.DrawArc(new Pen(color.BorderInCenter, 1), x - 8, y - 3, 15, 15, 0, 360);
            g.DrawArc(new Pen(color.BorderIn, 2), x - 7, y - 2, 13, 13, 0, 360);
        }

        private void DrawDirectAngle(Bitmap bitmap, Graphics g, RotateFlipType rf, Point pos)
        {
            Bitmap _bitmap = new Bitmap(bitmap);
            _bitmap.RotateFlip(rf);
            g.DrawImage(_bitmap, pos);
        }

        private void RedrawModel()
        {            
            lock (backGroundImage)
            {
                Bitmap b = new Bitmap(backGroundImage);
                Graphics g = Graphics.FromImage(b);
                foreach (Streetlight streelight in Manager.streetlights)
                    PaintStreetlight(g, streelight);
                foreach (CityCar car in Manager.cars)
                    PaintCar(g, car);
                g.Dispose();
                try
                {
                    pictureBox.Invoke(new VoidDelegate(() => pictureBox.Image = b));
                }
                catch (Exception)
                {
                    Thread.CurrentThread.Abort();
                }
            }
            Thread.CurrentThread.Abort();
        }    

        private void PaintCar(Graphics g, Car car)
        {
            if (car.CurrentAngle == 0)
            {
                DrawDirectAngle(carImage, g, RotateFlipType.RotateNoneFlipNone, car);
            }
            else if (car.CurrentAngle == Math.PI / 2)
            {
                DrawDirectAngle(carImage, g, RotateFlipType.Rotate90FlipNone, car);
            }
            else if (car.CurrentAngle == Math.PI)
            {
                DrawDirectAngle(carImage, g, RotateFlipType.Rotate180FlipNone, car);
            }
            else if (car.CurrentAngle == 3 * Math.PI / 2)
            {
                DrawDirectAngle(carImage, g, RotateFlipType.Rotate270FlipNone, car);
            }
            else
            {
                g.DrawImage(carImage, new Point[] { car.LeftHighCorner, car.RightHighCorner, car.LeftLowCorner });
            }            
        } 

        #endregion

        #region FormEvents

        private void Form1_DoubleClick(object sender, EventArgs e)
        {
            
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            foreach (CityCar car in Manager.cars)
                car.Go();
        }

        void pictureBox_MouseClick(object sender, MouseEventArgs e)
        {
            
        }        

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            
        }

        #endregion

        private void Form1_MouseClick(object sender, MouseEventArgs e)
        {
            //Manager.car.Destination = new modelPoint(285, 300);
            //Manager.car.Destination = new modelPoint(360, 195);
            Manager.ind = true;
        }
    }

    public delegate void VoidDelegate();
    public delegate void GraphicsDelegate(Graphics g);

    public struct Colors
    {
        public Color MainColor;
        public Color BorderOut;
        public Color BorderOutCenter;
        public Color BorderCenter;
        public Color BorderInCenter;
        public Color BorderIn;
        public Color Light;
    }
}
